﻿using System;
using System.Windows.Automation;
using ProdControls.Interfaces;
using ProdControls.UIAPatterns;
using ProdControls.Utility;
using ProdControls.Verification;
using ProdLogging;

namespace ProdControls.Bridges
{
    public static class ValueBridge
    {
        #region Required

        /// <summary>
        ///   Sets the text contained in the current TextBox
        /// </summary>
        /// <param name="extension"> The extended interface. </param>
        /// <param name="control"> The UI Automation element </param>
        /// <param name="text"> The text to place into the ProdTextBox. </param>
        public static void SetValueHook(this IValue extension, BaseProdControl control, string text)
        {
            if ((bool) control.UIAElement.GetCurrentPropertyValue(ValuePattern.IsReadOnlyProperty))
                throw new ArgumentException("TextBox is Read Only");
            try
            {
                UiaSetValue(control, text);
            }
            catch (InvalidOperationException)
            {
                /* now try a native SendMessage */
                NativeSetValue(control, text);
            }
        }

        private static void UiaSetValue(BaseProdControl control, string text)
        {
            LogController.ReceiveLogMessage(new LogMessage(text));
            AutomationEventVerifier.Register(new EventRegistrationMessage(control, ValuePattern.ValueProperty));
            ValuePatternHelper.SetValue(control.UIAElement, text);
        }

        private static void NativeSetValue(BaseProdControl control, string text)
        {
            ProdTextBoxNative.SetTextNative((IntPtr) control.UIAElement.Current.NativeWindowHandle, text);
        }

        /// <summary>
        ///   Gets or sets the text contained in the current TextBox
        /// </summary>
        /// <param name="extension"> The extended interface. </param>
        /// <param name="control"> The UI Automation element </param>
        /// <returns> The text currently in the ProdTextBox </returns>
        public static string GetValueHook(this IValue extension, BaseProdControl control)
        {
            try
            {
                return UiaGetValue(control);
            }
            catch (InvalidOperationException)
            {
                /* now try a native SendMessage */
                return NativeGetValue(control);
            }
        }

        private static string UiaGetValue(BaseProdControl control)
        {
            string ret = ValuePatternHelper.GetValue(control.UIAElement);
            LogController.ReceiveLogMessage(new LogMessage("String: " + ret));
            return ret;
        }

        private static string NativeGetValue(BaseProdControl control)
        {
            return ProdTextBoxNative.GetTextNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);
        }

        /// <summary>
        ///   Gets the read only state of the control.
        /// </summary>
        /// <param name="extension"> The extension. </param>
        /// <param name="control"> The control. </param>
        /// <returns> <c>true</c> if in a ReadOnly state; otherwise, <c>false</c> . </returns>
        public static bool GetReadOnlyHook(this IValue extension, BaseProdControl control)
        {
            return ValuePatternHelper.GetIsReadOnly(control.UIAElement);
        }

        #endregion Required

        /// <summary>
        ///   Appends text to a text input control
        /// </summary>
        /// <param name="extension"> The extended interface. </param>
        /// <param name="control"> The UI Automation element </param>
        /// <param name="newText"> Text To Append </param>
        public static void AppendValueHook(this IValue extension, BaseProdControl control, string newText)
        {
            try
            {
                UiaAppendValue(control, newText);
            }
            catch (InvalidOperationException)
            {
                /* now try a native SendMessage */
                NativeAppendValue(control, newText);
            }
        }

        private static void UiaAppendValue(BaseProdControl control, string newText)
        {
            if (ValuePatternHelper.GetIsReadOnly(control.UIAElement))
                throw new ArgumentException("Control is Read Only");

            AutomationEventVerifier.Register(new EventRegistrationMessage(control, ValuePattern.ValueProperty));

            LogController.ReceiveLogMessage(new LogMessage("Appending: " + newText));
            ValuePatternHelper.AppendValue(control.UIAElement, newText);
        }

        private static void NativeAppendValue(BaseProdControl control, string newText)
        {
            int hwnd = control.UIAElement.Current.NativeWindowHandle;
            if (hwnd == 0)
                /* If it doesn't have one, send keys, then */
                InternalUtilities.SendKeysAppendText(control.UIAElement, newText);

            //ProdEditNative.AppendTextNative((IntPtr) control.UIAElement.Current.NativeWindowHandle, newText);
        }

        /// <summary>
        ///   Set text area value to an empty string
        /// </summary>
        /// <param name="extension"> The extended interface. </param>
        /// <param name="control"> The UI Automation element </param>
        public static void ClearValueHook(this IValue extension, BaseProdControl control)
        {
            try
            {
                UiaClearValue(control);
            }
            catch (InvalidOperationException)
            {
                /* now try a native SendMessage */
                NativeClearValue(control);
            }
        }

        private static void UiaClearValue(BaseProdControl control)
        {
            if (ValuePatternHelper.GetIsReadOnly(control.UIAElement))
                throw new ArgumentException("Control is Read Only");
            //currently the verification is done in pattern helper
            ValuePatternHelper.SetValue(control.UIAElement, "");
            LogController.ReceiveLogMessage(new LogMessage("Clear Text"));
        }

        private static void NativeClearValue(BaseProdControl control)
        {
            int hwnd = control.UIAElement.Current.NativeWindowHandle;
            if (hwnd != 0)
            {
                // ProdEditNative.ClearTextNative((IntPtr) hwnd);
            }

            /* If it doesn't have one, send keys, then */
            InternalUtilities.SendKeysSetText(control.UIAElement, "^a");
            InternalUtilities.SendKeysSetText(control.UIAElement, "{Backspace}");
        }

        /// <summary>
        ///   Gets the number of characters in textbox
        /// </summary>
        /// <param name="extension"> The extended interface. </param>
        /// <param name="control"> The UI Automation element </param>
        /// <returns> The number of characters in the ProdTextBox </returns>
        /// <remarks>
        ///   Will attempt to match AutomationId, then ReadOnly
        /// </remarks>
        public static int GetLengthHook(this IValue extension, BaseProdControl control)
        {
            try
            {
                return UiaGetLength(control);
            }
            catch (InvalidOperationException)
            {
                /* now try a native SendMessage */
                return NativeGetLength(control);
            }
        }

        private static int UiaGetLength(BaseProdControl control)
        {
            string txt = ValuePatternHelper.GetValue(control.UIAElement);
            int retVal = txt.Length;
            LogController.ReceiveLogMessage(new LogMessage("Length: " + retVal));
            return retVal;
        }

        private static int NativeGetLength(BaseProdControl control)
        {
            string txt = ProdTextBoxNative.GetTextNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);
            return txt.Length;
        }

        /// <summary>
        ///   inserts the supplied string to the existing textBox text
        /// </summary>
        /// <param name="extension"> The extended interface. </param>
        /// <param name="control"> The UI Automation element </param>
        /// <param name="newText"> Text to append to TextBox value </param>
        /// <param name="index"> Zero based index of string to insert text into </param>
        public static void InsertValueHook(this IValue extension, BaseProdControl control, string newText,
                                           int index)
        {
            if ((bool) control.UIAElement.GetCurrentPropertyValue(ValuePattern.IsReadOnlyProperty))
                throw new ArgumentException("TextBox is Read Only");

            UiaInsertValue(control, newText, index);
        }

        private static void UiaInsertValue(BaseProdControl control, string newText, int index)
        {
            LogController.ReceiveLogMessage(new LogMessage("inserting " + newText));
            AutomationEventVerifier.Register(new EventRegistrationMessage(control, ValuePattern.ValueProperty));
            ValuePatternHelper.InsertValue(control.UIAElement, newText, index);
        }

        /// <summary>
        ///   Determines whether the control is in a read only state.
        /// </summary>
        /// <param name="control"> The control. </param>
        /// <returns> <c>true</c> if control is read only, <c>true</c> ; otherwise, <c>false</c> . </returns>
        public static bool IsReadOnlyHook(BaseProdControl control)
        {
            return (bool) control.UIAElement.GetCurrentPropertyValue(ValuePattern.IsReadOnlyProperty);
        }
    }
}